/**
 * @author 陈泰来
 * @version V1.0
 * @Project echo-java-base
 * @Title 模拟银行
 * @Description *
 * @Package concurrent.example.bank
 * @date 2021/3/10 10:22 上午
 * @Copyright:学如逆水行舟，不进则退 .
 */
package concurrent.bank;

import java.util.Arrays;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Bank {
    /**
     * @author chentl
     * @description 账户数组
     * @date 2021/3/17 9:38 上午
     * @params
     * @return
     */
    private final double[] accounts;

    /**
     * @Description 银行转账可重入锁   默认创建的是不公平锁，因为公平锁会导致性能降低;
     * 公平锁： 公平锁偏爱等待时间最长的线程，但是这一举措会导致性能大大降低
     * @Author chentl
     * @Create: 2021/3/17 11:42 上午
     */
    private final Lock bankLock;

    /**
     * @Description 余额充足条件对象
     * @Author chentl
     * @Create: 2021/3/17 11:59 上午
     */
    private Condition sufficientFunds;

    /**
     * @return
     * @author chentl
     * @description 银行账户的构造
     * @date 2021/3/10 10:27 上午
     * @params [n 账户总数, initialBalance 初始金额]
     */
    public Bank(int n, double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);

        bankLock = new ReentrantLock();
        sufficientFunds = bankLock.newCondition();
    }

    public void transfer(Vector<Double> accounts, int from, int to, double amount) {
        synchronized (accounts) {

            accounts.set(from, accounts.get(from) - amount);
            accounts.set(to, accounts.get(to) + amount);
        }
        System.out.println("...");
    }

    /**
     * @return void
     * @author chentl
     * @description 将资金 从一个账户转移到另一个账户
     * @date 2021/3/10 10:30 上午
     * @params [from, to, amount]
     */
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
        System.out.printf("*\t%d 即将转给 %d %10.2f ,正在进行转账前检查,当前账户余额: %10.2f\t*\n", from, to, amount, getCurrentAccountBalance(from));

        if(bankLock.tryLock(5, TimeUnit.SECONDS)){
            try{
            sufficientFunds = bankLock.newCondition();
            sufficientFunds.awaitUninterruptibly();
            }finally {
                bankLock.unlock();
            }
        }

        while (accounts[from] < amount) {
            System.out.printf("*\t%d 余额不足，线程等待\n", from);
            wait();
        }

        accounts[from] -= amount;
        System.out.printf("*\t%d 转给 %d %10.2f\n", from, to, amount);
        accounts[to] += amount;


        System.out.printf("*\t当前账户余额: %10.2f\n", getCurrentAccountBalance(from));
        System.out.printf("*\t当前银行总金额: %10.2f\n", getTotalBalance());

        //转账成功之后唤醒其他线程重新检查条件
//        notifyAll();
        notify();//导致死锁

    }

    /**
     * @return double
     * @author chentl
     * @description 获取所有账户总金额
     * @date 2021/3/10 10:32 上午
     * @params []
     */
    public synchronized double getTotalBalance() {
        double sum = 0;
        for (double a : accounts)
            sum += a;
        return sum;
    }

    public synchronized double getCurrentAccountBalance(int current) {
        return accounts[current];

    }

    /**
     * @return int
     * @author chentl
     * @description 获取银行中所有的账户数量
     * @date 2021/3/10 10:33 上午
     * @params []
     */
    public int size() {
        return accounts.length;
    }
}
